#include "scenes/critterding/evolution.h"
#include "utils/settings.h"
#include "utils/dirlayout.h"
#include "filesystem/be_filesystem.h"

using namespace std;

int main(int argc, char* argv[])
{
	// setup roothpaths
#if !defined(WIN32)
	std::string home( getenv("HOME") );
	home.append( "/.critterding/" );
	BeFilesystem::Instance()->getRootPaths().push(home);
	
	// parse argv[0] for binary path
	string path(argv[0]);
	size_t pos = path.find_last_of("/", path.size());
	std::stringstream buff;
	if ( pos != string::npos )
		buff << path.substr( 0, pos+1 );
	
	buff << "../share/critterding/";
	BeFilesystem::Instance()->getRootPaths().push( buff.str() );
#else
	BeFilesystem::Instance()->getRootPaths().push( "critterding/" );
#endif		
	
	Settings *settings = Settings::Instance();
	
	// settings belonging to Critterding
	settings->registerCVar("threads",						1, 1, 16, false, "threads to use");
	settings->registerCVar("startseed",						0, 0, 4000000000, true, "startseed for random number generation");
	settings->registerCVar("benchmark",						0, 0, 1, true, "run the critterding benchmark");

	settings->registerCVar("race",							0, 0, 1, false, "enable race simulation");
	settings->registerCVar("roundworld",						0, 0, 1, false, "enable round planet");
	settings->registerCVar("concavefloor",						0, 0, 1, false, "enable concave floor");
	settings->registerCVar("testworld",						0, 0, 1, false, "a world for test purposes");

	settings->registerCVar("worldsizeX",						15, 1, 5000, false, "size of the world along axis X");
	settings->registerCVar("worldsizeY",						10, 1, 5000, false, "size of the world along axis Y");
	settings->registerCVar("worldsizeZ",						10, 0, 5000, false, "height of hills using concave floor");
	settings->registerCVar("worldwalls",						1, 0, 1, false, "enable walls around the world");

	settings->registerCVar("killhalf_decrenergypct",				1, 0, 100, false, "decrease energy by n percent when killhalfat triggers");
	settings->registerCVar("killhalf_incrworldsizeX",				0, 0, 100, false, "increase worldsizeX by n when killhalfat triggers");
	settings->registerCVar("killhalf_incrworldsizeY",				0, 0, 100, false, "increase worldsizeY by n when killhalfat triggers");
	settings->registerCVar("killhalf_decrmaxlifetimepct",				0, 0, 100, false, "decrease critter_maxlifetime by n when killhalfat triggers");
	
	settings->registerCVar("energy",						400, 0, 1000000, false, "energy in the system by number of food cubes");
	settings->registerCVar("mincritters",						10, 0, 1000, false, "minimum number of critters");

	settings->registerCVar("retinasperrow",						20, 1, 1000, false, "number of vision retinas to stack per row onscreen");
	settings->registerCVar("camerasensitivity",					20, 1, 1000, false, "sensitivity of the camera");

  settings->registerCVar("maximumimpulse",              5000, 0, 1000000, false, "maximum impulse per-tick");
  settings->registerCVar("absolutemotorneurons",              0, 0, 1, true, "muscle neurons determine angle + dt directly");
  settings->registerCVar("selfcollisions",              0, 0, 1, true, "critters can exploit physics glitches");

	settings->registerCVar("colormode",						0, 0, 1, true, "colors genetically exact critters identically");
	settings->registerCVar("exit_if_empty",						0, 0, 1, true, "exit simulation if there are no critters");
	settings->registerCVar("autoload",						0, 0, 1, true, "autoload critters from ~/.critterding/load");
	settings->registerCVar("autoloadlastsaved",					0, 0, 1, true, "autoload critters from ~/.critterding/lastsaved");

	settings->registerCVar("critter_insertevery",					0, 0, 1000000, false, "inserts a random critter every n frames");
	settings->registerCVar("critter_maxlifetime",					10000, 1, 1000000, false, "maximum number of frames a critter lives");
	settings->registerCVar("critter_maxenergy",					5000, 1, 1000000, false, "maximum amount of energy a critter has");

	settings->registerCVar("critter_startenergy",					3000, 1, 1000000, false, "energy a new critter (adam) starts with");
	settings->registerCVar("critter_procinterval",					20, 1, 1000000, false, "minimum frames between procreations");
	settings->registerCVar("critter_minenergyproc",					3000, 1, 1000000, false, "energy a critters needs to procreate");
	settings->registerCVar("critter_sightrange",					30, 1, 1000000, false, "distance a critter can see (10 = 1 worldsize)");

	settings->registerCVar("critter_retinasize",					8, 1, 1000, false, "size of a critters eye retina");
	settings->registerCVar("critter_autosaveinterval",				0, 0, 1000000, false, "save critters every n seconds");
	settings->registerCVar("critter_autoexchangeinterval",				0, 0, 1000000, false, "exchange critters every n seconds");
	settings->registerCVar("critter_killhalfat",					120, 2, 1000000, false, "kill 50% of critters if population reaches n");
	settings->registerCVar("critter_enableomnivores",					0, 0, 1, true, "enables critters to eat each other");
	settings->registerCVar("critter_raycastvision",					0, 0, 1, true, "use raycast vision instead of opengl");
	
	settings->registerCVar("food_maxlifetime",					10000, 1, 1000000, false, "maximum number of frames a food unit exists");
	settings->registerCVar("food_maxenergy",						1500, 1, 1000000, false, "maximum amount of energy a food unit has");
	settings->registerCVar("food_size",						200, 1, 1000000, false, "size of a food unit");
	settings->registerCVar("food_scale",          					0, 0, 1, false, "scale food when consumed");

	settings->registerCVar("body_maxmutations",					5, 1, 1000000, false, "maximum mutations on a body mutant");
	settings->registerCVar("body_mutationrate",					5, 0, 100, false, "percentage of newborns that mutate bodies");

	settings->registerCVar("body_minbodyparts",					2, 0, 1000000, false, "minimum body parts per critter");
	settings->registerCVar("body_maxbodyparts",					30, 0, 1000000, false, "maximum body parts per critter");
	settings->registerCVar("body_minbodypartsatbuildtime",				4, 1, 1000000, false, "minimum body parts for a new critter");
	settings->registerCVar("body_maxbodypartsatbuildtime",				8, 1, 1000000, false, "maximum body parts for a new critter");
	settings->registerCVar("body_maxheads",					    	1, 1, 1000000, false, "maximum heads per critter");
	settings->registerCVar("body_percentchance_head",				1, 1, 1000000, false, "chance a bodypart will be a head");

	settings->registerCVar("body_minbodypartsize",					20, 1, 1000000, false, "minimum size of a critters body part");
	settings->registerCVar("body_maxbodypartsize",					200, 1, 1000000, false, "maximum size of a critters body part");

	settings->registerCVar("body_percentmutateeffectchangecolor",			1, 0, 100, false, "chance of changing body color");
	settings->registerCVar("body_percentmutateeffectchangecolor_slightly",		5, 0, 100, false, "chance of changing body color");
	settings->registerCVar("body_percentmutateeffectaddbodypart",			2, 0, 100, false, "chance of adding a body part");
	settings->registerCVar("body_percentmutateeffectremovebodypart",			2, 0, 100, false, "chance of removing a body part");
	settings->registerCVar("body_percentmutateeffectresizebodypart",			2, 0, 100, false, "chance of resizing a body part");
	settings->registerCVar("body_percentmutateeffectresizebodypart_slightly",		5, 0, 100, false, "chance of slightly resizing a body part");
	settings->registerCVar("body_percentmutateeffectchangeconstraintlimits",		2, 0, 100, false, "chance of changing a joints motion limits");
	settings->registerCVar("body_percentmutateeffectchangeconstraintlimits_slightly",	5, 0, 100, false, "chance of slightly changing a joints motion limits");
	settings->registerCVar("body_percentmutateeffectchangeconstraintangles",		2, 0, 100, false, "chance of changing a joints position angles");
	settings->registerCVar("body_percentmutateeffectchangeconstraintangles_slightly",	5, 0, 100, false, "chance of changing a joints position angles");
	settings->registerCVar("body_percentmutateeffectchangeconstraintposition",	2, 0, 100, false, "chance of changing a joints position");
	settings->registerCVar("body_percentmutateeffectchangeconstraintposition_slightly", 5, 0, 100, false, "chance of slightly changing a joints position");

	settings->registerCVar("brain_maxmutations",					10, 1, 1000000, false, "maximum mutations on a brain mutant");
	settings->registerCVar("brain_mutationrate",					7, 0, 100, false, "percentage of newborns that mutate brains");

	settings->registerCVar("brain_maxneurons",					1000, 1, 1000000, false, "maximum neurons per critter");
	settings->registerCVar("brain_minsynapses",					1, 1, 1000000, false, "minimum synapses per neuron");
	settings->registerCVar("brain_maxsynapses",					1000, 1, 1000000, false, "maximum synapses per neuron");
	settings->registerCVar("brain_minneuronsatbuildtime",				20, 1, 1000000, false, "minimum neurons for a new critter");
	settings->registerCVar("brain_maxneuronsatbuildtime",				100, 1, 1000000, false, "maximum neurons for a new critter");

	settings->registerCVar("brain_minsynapsesatbuildtime",				5, 1, 1000000, false, "minimum synapses for a new neuron");
	settings->registerCVar("brain_maxsynapsesatbuildtime",				80, 1, 1000000, false, "maximum synapses for a new neuron of a new critter");

	settings->registerCVar("brain_percentchanceinhibitoryneuron",			50, 0, 100, false, "percent chance a neuron is inhibotory");
	settings->registerCVar("brain_mutate_percentchanceinhibitoryneuron",		0, 0, 1, true, "mutate this value");

	settings->registerCVar("brain_percentchancemotorneuron",				100, 0, 100, false, "percent chance a neuron is a motor neuron");
	settings->registerCVar("brain_mutate_percentchancemotorneuron",			0, 0, 1, true, "mutate this value");

	settings->registerCVar("brain_percentchanceplasticneuron",			20, 0, 100, false, "percent chance a neuron has plastic synapses");
	settings->registerCVar("brain_mutate_percentchanceplasticneuron",			0, 0, 1, true, "mutate this value");

	settings->registerCVar("brain_minplasticitystrengthen",				100, 1, 1000000, false, "minimum weight by which plastic synapses strengthen");
	settings->registerCVar("brain_maxplasticitystrengthen",				1000, 1, 1000000, false, "maximum weight by which plastic synapses strengthen");
	settings->registerCVar("brain_minplasticityweaken",				1000, 1, 1000000, false, "minimum weight by which plastic synapses weaken");
	settings->registerCVar("brain_maxplasticityweaken",				10000, 1, 1000000, false, "maximum weight by which plastic synapses weaken");
	settings->registerCVar("brain_mutate_plasticityfactors",				0, 0, 1, true, "mutate min/max plasticity values");

	settings->registerCVar("brain_minfiringthreshold",				2, 1, 1000000, false, "minimum firingthreshold of a neuron");
	settings->registerCVar("brain_mutate_minfiringthreshold",				0, 0, 1, true, "mutate this value");

	settings->registerCVar("brain_maxfiringthreshold",				10, 1, 1000000, false, "maximum firingthreshold of a neuron");
	settings->registerCVar("brain_mutate_maxfiringthreshold",				0, 0, 1, true, "mutate this value");

// 	settings->registerCVar("brain_maxdendridicbranches",				3, 1, 1000000, false, "maximum number of dendrites per neuron");
// 	settings->registerCVar("brain_mutate_maxdendridicbranches",			0, 0, 1, true, "mutate this value");

	settings->registerCVar("brain_percentchanceconsistentsynapses",			0, 0, 100, false, "percent chance a neurons synapses are all inhibitory or excitatory");
	settings->registerCVar("brain_mutate_percentchanceconsistentsynapses",			0, 0, 1, true, "mutate this value");

	settings->registerCVar("brain_percentchanceinhibitorysynapses",			50, 0, 100, false, "percent chance a synapse is inhibitory");
	settings->registerCVar("brain_mutate_percentchanceinhibitorysynapses",			0, 0, 1, true, "mutate this value");

	settings->registerCVar("brain_percentchancesensorysynapse",			20, 0, 100, false, "percent change a synapse connects to an input");
	settings->registerCVar("brain_mutate_percentchancesensorysynapse",			0, 0, 1, true, "mutate this value");

	settings->registerCVar("brain_percentmutateeffectaddneuron",			1, 0, 100, false, "chance of adding a neuron");
	settings->registerCVar("brain_percentmutateeffectremoveneuron",			1, 0, 100, false, "chance of removing a neuron");
	settings->registerCVar("brain_percentmutateeffectalterneuron",			2, 0, 100, false, "chance of altering a neuron");
	settings->registerCVar("brain_percentmutateeffectaddsynapse",			5, 0, 100, false, "chance of adding a synapse");
	settings->registerCVar("brain_percentmutateeffectremovesynapse",		5, 0, 100, false, "chance of removing a synapse");
	settings->registerCVar("brain_mutate_mutateeffects",					0, 0, 1, true, "mutate mutation effects");

	settings->registerCVar("brain_percentmutateeffectaltermutable",			1, 0, 100, false,"mutate value of a mutatable option");

	settings->registerCVar("brain_costhavingneuron",				20, 0, 1000000, false, "cost of having a neuron (1/100000 energy)");
	settings->registerCVar("brain_costfiringneuron",				20, 0, 1000000, false, "cost of firing a neuron");
	settings->registerCVar("brain_costfiringmotorneuron",				100, 0, 1000000, false, "cost of firing a motor neuron");
	settings->registerCVar("brain_costhavingsynapse",				20, 0, 1000000, false, "cost of having a synapse");
	
	settings->doCommandLineOptions(argc,argv );
	
	// MAIN LOOP

// 		boost::scoped_ptr<Scene> mainscene(new Scene( argc, argv ));
		Evolution* mainscene = new Evolution( argc, argv );
		while( !mainscene->m_exitscene )
			mainscene->draw();
		delete mainscene;
	
	return 0;

}
